<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <title>event-sequence</title>
  <style>
    html :focus {
      outline: 3px solid hotpink;
    }
  </style>
</head>
<body>

  <h1>Focus Event Sequence Test</h1>
  <p>First Tab through the elements, then click each element, then press <kbd>escape</kbd></p>

  <input type="text" data-label="first">
  <input type="text" data-label="second">
  <div onclick="" tabindex="0" data-label="third">third</div>
  <div onclick="" tabindex="-1" data-label="fourth"><a href="#void" data-label="fifth">fifth</a></div>


  <hr>
  <h2 id="output-results">Results</h2>
  <pre id="results">click tab order to update the output of results</pre>

  <script src="../../node_modules/platform/platform.js"></script>
  <script src="../../dist/amd/prototype/window.requestanimationframe.js"></script>
  <script>
    (function() {
      var log = document.getElementById('results');
      var history = [];
      var buffer = [];

      function elementName(element) {
        var value = element && element.getAttribute && element.getAttribute('data-label') || element && element.nodeName || 'none';
        return value;
      }

      function bufferEvent(event, target, related) {
        buffer.push({
          event: event.type,
          target: elementName(target || event.target),
          related: elementName(related || event.relatedTarget),
        });
      }

      var breakerTimeout;
      function breaker() {
        clearTimeout(breakerTimeout);
        breakerTimeout = setTimeout(function() {
          //log.textContent += "---------------------------------------------\n";
          history.push(buffer.slice(0));
          buffer.length = 0;
        }, 500);
      }

      function logFocusEvent(event) {
        //log.textContent += event.type + ': ' + elementName(event.target) + ', related: ' + elementName(event.relatedTarget) + "\n";
        bufferEvent(event);
        breaker();
      }

      function logPointerEvent(event) {
        //log.textContent += event.type + ': ' + elementName(event.target) + "\n";
        bufferEvent(event);
        breaker();
      }

      function logKeyEvent(event) {
        var code = event.keyCode || event.which;
        if (code != 9) {
          return;
        }

        //log.textContent += event.type + ': ' + elementName(event.target) + "\n";
        bufferEvent(event);
        breaker();
      }

      function logInputEvent(event) {
        bufferEvent(event);
        breaker();
      }

      function logActiveElementEvent(event) {
        //log.textContent += 'active-element' + ': ' + elementName(event.detail.focus) + ', related: ' + elementName(event.detail.blur) + "\n";
        bufferEvent(event, event.detail.focus, event.detail.blur);
        breaker();
      }

      // https://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order
      // https://www.w3.org/TR/DOM-Level-3-Events/#legacy-focusevent-events
      ['focus', 'blur', 'focusin', 'focusout', 'DOMFocusIn', 'DOMFocusOut', 'domfocusin', 'domfocusout'].forEach(function(eventName) {
        document.body.addEventListener(eventName, logFocusEvent, true);
      });

      ['mousedown', 'mouseup', 'click', 'touchstart', 'touchend', 'pointerdown', 'pointerup'].forEach(function(eventName) {
        document.body.addEventListener(eventName, logPointerEvent, true);
      });

      ['input', 'beforeinput'].forEach(function(eventName) {
        document.body.addEventListener(eventName, logInputEvent, true);
      });

      ['keydown', 'keyup', 'keypress'].forEach(function(eventName) {
        document.body.addEventListener(eventName, logKeyEvent, true);
      });

      document.body.addEventListener('active-element', logActiveElementEvent, true);

      function unregisterLogEvents() {
        ['focus', 'blur', 'focusin', 'focusout'].forEach(function(eventName) {
          document.body.removeEventListener(eventName, logFocusEvent, true);
        });

        ['mousedown', 'mouseup', 'click', 'touchstart', 'touchend', 'pointerdown', 'pointerup'].forEach(function(eventName) {
          document.body.removeEventListener(eventName, logPointerEvent, true);
        });

        ['keydown', 'keyup', 'keypress'].forEach(function(eventName) {
          document.body.removeEventListener(eventName, logKeyEvent, true);
        });

        document.body.removeEventListener('active-element', logActiveElementEvent, true);
      }

      log.addEventListener('click', function(event) {
        unregisterLogEvents();
        //log.textContent += 'observation stopped';

        var result = document.createElement('textarea');
        result.style.width = '100%';
        result.style.height = '400px';
        document.body.replaceChild(result, log);
        result.value += JSON.stringify({
          platform: window.platform,
          events: history,
        }, null, 2);
      }, true);

      (function() {
        var previousActiveElement = document.activeElement;
        function observeActiveElement() {
          if (document.activeElement !== previousActiveElement) {
            // https://developer.mozilla.org/en/docs/Web/API/CustomEvent
            var activeElementEvent = new CustomEvent('active-element', {
              bubbles: false,
              cancelable: false,
              detail: {
                focus: document.activeElement,
                blur: previousActiveElement,
              }
            });

            document.body.dispatchEvent(activeElementEvent);
            previousActiveElement = document.activeElement;
          }

          requestAnimationFrame(observeActiveElement);
        }

        observeActiveElement();
      })();
    })();
  </script>

</body>
</html>
